package com.knowledge.plus.创建线程and线程池.注解创建线程.config;

import com.easy.utils.ThreadsUtil;
import com.knowledge.plus.创建线程and线程池.注解创建线程.config.properties.ThreadPoolProperties;
import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * 线程池配置
 *
 * @author TPF
 * @since 2022/9/29
 */
@Configuration
public class ThreadPoolTaskConfig {

    /**
     * 核心线程数 = cpu 核心数 + 1
     */
    private final int core = Runtime.getRuntime().availableProcessors() + 1;

    @Autowired
    private ThreadPoolProperties threadPoolProperties;

    /**
     * 使用该bean需要添加：@Component、@EnableAsync
     */
    @Bean(name = "threadPoolTaskExecutor")
    @ConditionalOnProperty(prefix = "thread-pool", name = "enabled", havingValue = "true")
    public ThreadPoolTaskExecutor threadPoolTaskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(core);  // 核心线程数: 线程池创建的时候初始化的线程数
        executor.setMaxPoolSize(core * 2);  // 最大线程数: 线程池最大的线程数,只有在缓冲队列满了之后才会申请超过核心线程数的线程
        executor.setQueueCapacity(threadPoolProperties.getQueueCapacity()); // 缓冲队列200: 用来缓冲执行任务的队列
        executor.setKeepAliveSeconds(threadPoolProperties.getKeepAliveSeconds()); // 允许线程的空闲时间 秒" 当超过核心线程数之外的线程在空闲时间到达之后会被销毁
        executor.setThreadNamePrefix("asyncTask-"); // 线程池名的前缀: 设置好了之后可以方便我们定位处理任务所在的线程池
        // 线程池对拒绝任务的处理策略: 这里采用了CallerRunsPolicy策略,当线程池没有处理能力的时候,
        // 该策略会直接在execute方法的调用线程中运行被拒绝的任务;如果执行程序已关闭,则会丢弃该任务
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        return executor;
    }

    /**
     * 执行周期性或定时任务
     */
    @Bean(name = "scheduledExecutorService")
    protected ScheduledExecutorService scheduledExecutorService() {
        return new ScheduledThreadPoolExecutor(core,
                new BasicThreadFactory.Builder().namingPattern("schedule-pool-%d").daemon(true).build(),
                new ThreadPoolExecutor.CallerRunsPolicy()) {
            @Override
            protected void afterExecute(Runnable r, Throwable t) {
                super.afterExecute(r, t);
                ThreadsUtil.printException(r, t);
            }
        };
    }
}
